# 导入数据库连接的包
import mysql.connector
import random

# 从文件中读取数据库相关信息
with open("database_info", "r") as db:
    db_info = db.read().split(",")
    db_host = db_info[0]
    db_user = db_info[1]
    db_password = db_info[2]

# 配置数据库连接信息
my_db = mysql.connector.connect(
    host=db_host,
    user=db_user,
    passwd=db_password,
    database="artificial_intelligence",
    auth_plugin='mysql_native_password'
)

# 获取游标
my_cursor = my_db.cursor()
# 执行sql语句
my_cursor.execute("select * from prostate_cancer")
# 从游标中取出结果
data = my_cursor.fetchall()

# 分组
# 将数据打乱
random.shuffle(data)
n = len(data) // 3
# 测试集数据(前n行)
test_set = data[0:n]
# 训练集数据（剩余的数据）
train_set = data[n:]


# KNN
# 距离
def distance_euclidean_metric(d1, d2):
    # 初始化结果
    res = 0

    # 计算欧氏距离的平方
    for key in range(2, 10):
        res += (float(d1[key]) - float(d2[key])) ** 2

    # 返回欧氏距离
    return res ** 0.5


def distance_manhattan(d1, d2):
    # 初始化结果
    res = 0

    # 计算曼哈顿距离
    for key in range(2, 10):
        res += abs(float(d1[key]) - float(d2[key]))

    # 返回曼哈顿距离
    return res


def distance_chebyshev(d1, d2):
    # 初始化结果
    res = 0

    # 计算切比雪夫距离
    for key in range(2, 10):
        temp = abs(float(d1[key]) - float(d2[key]))
        if temp > res:
            res = temp

    # 返回切比雪夫距离
    return res


# 近邻值k的选取
K = 9


def knn(test_data):
    # 1、距离
    res = [
        {"result": train[1], "distance": distance_chebyshev(test_data, train)}
        for train in train_set
    ]

    # 2、排序
    res = sorted(res, key=lambda item: item['distance'])

    # 3、取前K个
    res_k = res[0:K]

    # 4、加权计算结果
    # 初始化结果
    result = {'B': 0, 'M': 0}
    # 计算总距离
    distance_sum = 0
    for r in res_k:
        distance_sum += r['distance']

    # 计算结果
    for r in res_k:
        result[r['result']] += 1 - r['distance'] / distance_sum

    # 返回最终结果
    if result['B'] > result['M']:
        return 'B'
    else:
        return 'M'


# 计算正确率
# 初始化正确个数
def accuracy():
    correct = 0
    for test in test_set:
        # 真实结果
        result_real = test[1]
        # 预测结果
        result_prediction = knn(test)

        if result_prediction == result_real:
            correct += 1

    print("准确率：{:.2f}%".format(100 * correct / len(test_set)))


if __name__ == '__main__':
    accuracy()
